/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version TWICE.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-TWICE.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sevenheaven.segmentcontrol;

import com.sevenheaven.segmentcontrol.utils.Misc;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import timber.log.Timber;

/**
 * Customized Element, fix radius corner fill overflow
 *
 * @since 2021-04-25
 */
public class RadiusElement extends ShapeElement {
    private static final int TWICE = 2;
    private static final int ANGLE_90 = 90;
    private static final int ANGLE_180 = 180;

    private int topLeftRadius;
    private int topRightRadius;
    private int bottomLeftRadius;
    private int bottomRightRadius;

    private final Rect prevSetBoundsParam = new Rect();

    private final Paint paint;
    private final boolean isStroke;
    private int strokeWidth = 0;
    private Color strokeColor = Color.CYAN;
    private Color fillColor;

    private Path path;

    /**
     * 构造函数
     *
     * @param isStroke 是否绘制边框
     */
    public RadiusElement(boolean isStroke) {
        this.isStroke = isStroke;
        paint = new Paint();
        paint.setAntiAlias(true);
    }

    @Override
    public void setCornerRadius(float radius) {
        this.topLeftRadius = (int) radius;
        this.topRightRadius = (int) radius;
        this.bottomLeftRadius = (int) radius;
        this.bottomRightRadius = (int) radius;
    }

    /**
     * 设置矩形圆角半径
     *
     * @param topLeft 左上角半径
     * @param topRight 右上角半径
     * @param bottomLeft 左下角半径
     * @param bottomRight 右下角半径
     */
    public void setRadius(int topLeft, int topRight, int bottomLeft, int bottomRight) {
        this.topLeftRadius = topLeft;
        this.topRightRadius = topRight;
        this.bottomLeftRadius = bottomLeft;
        this.bottomRightRadius = bottomRight;
    }

    @Override
    public void setStroke(int width, RgbColor color) {
        this.strokeColor = Misc.toUtilsColor(color);

        this.strokeWidth = width;
        if (!prevSetBoundsParam.isEmpty()) {
            setBounds(
                prevSetBoundsParam.left,
                prevSetBoundsParam.top,
                prevSetBoundsParam.right,
                prevSetBoundsParam.bottom);
        }
    }

    @Override
    public void setRgbColor(RgbColor color) {
        this.fillColor = Misc.toUtilsColor(color);
        Timber.d("setRgbColor, rgbColor=%d, fillColor=%d, redColor=%d",
            color.asArgbInt(), fillColor.getValue(), Color.BLUE.getValue());
    }

    @Override
    public void setBounds(int le, int tp, int rt, int bt) {
        int left = le;
        int top = tp;
        int right = rt;
        int bottom = bt;

        prevSetBoundsParam.set(left, top, right, bottom);
        Timber.d("setBounds inParam=%s", prevSetBoundsParam);
        Timber.d("setBounds radius(%d,%d - %d,%d)",
            topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);

        super.setBounds(left, top, right, bottom);

        // exclude stroke width
        if (isStroke) {
            int halfStrokeWidth = strokeWidth / TWICE;
            left += halfStrokeWidth;
            top += halfStrokeWidth;
            right -= halfStrokeWidth;
            bottom -= halfStrokeWidth;
        }

        path = new Path();
        path.moveTo(left + topLeftRadius, top);
        path.lineTo(right - topRightRadius, top);
        path.arcTo(new RectFloat(
            right - topRightRadius * TWICE, top, right, top + topRightRadius * TWICE),
            -ANGLE_90, ANGLE_90);
        path.lineTo(right, bottom - bottomRightRadius);
        path.arcTo(new RectFloat(
            right - bottomRightRadius * TWICE, bottom - bottomRightRadius * TWICE, right, bottom),
            0, ANGLE_90);
        path.lineTo(left + bottomLeftRadius, bottom);
        path.arcTo(
            new RectFloat(left, bottom - bottomLeftRadius * TWICE, left + bottomLeftRadius * TWICE,
            bottom), ANGLE_90, ANGLE_90);
        path.lineTo(left, top + topLeftRadius);
        path.arcTo(
            new RectFloat(left, top, left + topLeftRadius * TWICE, top + topLeftRadius * TWICE),
            ANGLE_180, ANGLE_90);
        path.close();
    }

    @Override
    public void drawToCanvas(Canvas canvas) {
        if (fillColor != null) {
            Timber.d("this=%s, drawToCanvas, bounds=%s, fillColor=%d, strokeColor=%d",
                    this, getBounds(), fillColor.getValue(), strokeColor.getValue());

            paint.setColor(fillColor);
            paint.setStyle(Paint.Style.FILL_STYLE);
            canvas.drawPath(path, paint);
        }

        if (strokeWidth > 0) {
            paint.setColor(strokeColor);
            paint.setStyle(Paint.Style.STROKE_STYLE);
            paint.setStrokeJoin(Paint.Join.MITER_JOIN);
            paint.setStrokeWidth(strokeWidth);
            canvas.drawPath(path, paint);
        }
    }
}